﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestForm
{
    public class Snake:ICloneable
    {
        public Random Random;

        public List<Body> Bodys;
        public List<Food> Foods;

        public short Width;
        public short Height;

        private Directions _Directions;
        private bool IsReDirection;

        public event Action GameOver;

        public int Score
        {
            get
            {
                return Bodys.Count - 3;
            }
        }

        public Directions Direction
        {
            get
            {
                return _Directions;
            }
            set
            {
                if (IsReDirection)
                {
                    return;
                }

                if (_Directions == Directions.Down && value == Directions.Up)
                {
                    return;
                }
                if (_Directions == Directions.Up && value == Directions.Down)
                {
                    return;
                }
                if (_Directions == Directions.Left && value == Directions.Right)
                {
                    return;
                }
                if (_Directions == Directions.Right && value == Directions.Left)
                {
                    return;
                }

                IsReDirection = true;

                _Directions = value;
            }
        }

        public void Next()
        {
            IsReDirection = false;

            if (Bodys.Count == 0)
            {
                return;
            }

            var Head = Bodys[0];
            var Tail = Bodys[Bodys.Count - 1];

            switch (Direction)
            {
                case Directions.Up:
                    --Head.Y;
                    break;
                case Directions.Down:
                    ++Head.Y;
                    break;
                case Directions.Left:
                    --Head.X;
                    break;
                case Directions.Right:
                    ++Head.X;
                    break;
            }

            if (Head.X < 0 || Head.Y < 0 || Head.X >= Width || Head.Y >= Height)
            {
                if (GameOver != null)
                {
                    GameOver();
                }
                return;
            }

            for (int i = Bodys.Count - 2; i >= 1; --i)
            {
                if (Bodys[i].X == Head.X && Bodys[i].Y == Head.Y)
                {
                    if (GameOver != null)
                    {
                        GameOver();
                    }
                    return;
                }
            }

            for (int i = Bodys.Count - 1; i >= 1; --i)
            {
                Bodys[i] = Bodys[i - 1];
            }

            Bodys[0] = Head;

            var Count = Foods.RemoveAll(Item =>
            {
                if (Item.X == Head.X && Item.Y == Head.Y)
                {
                    Bodys.Add(Tail);

                    return true;
                }

                return false;
            });

            for (int i = 0; i < Count; i++)
            {
                AddFood();
            }
            return;
        }

        public Snake(short Width, short Height)
        {
            Random = new Random();
            Bodys = new List<Body>();
            Foods = new List<Food>();

            this.Width = Width;
            this.Height = Height;
        }

        public void AddFood()
        {
            var NewFood = new Food();

            AddFood:
            NewFood.X = (short)Random.Next(0, Width);
            NewFood.Y = (short)Random.Next(0, Height);

            if (Bodys.FindIndex(Item => { return Item.X == NewFood.X && Item.Y == NewFood.Y; }) != -1)
            {
                goto AddFood;
            }

            if (Foods.FindIndex(Item => { return Item.X == NewFood.X && Item.Y == NewFood.Y; }) != -1)
            {
                goto AddFood;
            }

            Foods.Add(NewFood);
        }

        public void Play()
        {
            IsReDirection = false;

            Direction = Directions.Right;

            Bodys.Clear();

            Foods.Clear();

            Bodys.Add(new Body(4, 2));
            Bodys.Add(new Body(3, 2));
            Bodys.Add(new Body(2, 2));

            AddFood();
        }
        private Snake()
        {

        }

        public object Clone()
        {
            var Result = new Snake();

            Result.Bodys = new List<Body>(this.Bodys);
            Result.Foods = new List<Food>(this.Foods);

            Result.Height = this.Height;
            Result.Width = this.Width;
            Result._Directions = this._Directions;
            Result.Random = this.Random;
            Result.IsReDirection = this.IsReDirection;

            return Result;
        }
    }
    public struct Body
    {
        public short X;
        public short Y;

        public Body(short X, short Y)
        {
            this.X = X;
            this.Y = Y;
        }
    }
    public struct Food
    {
        public short X;
        public short Y;
    }
    public enum Directions:int
    {
        Left = 0x1,
        Right = 0x2,
        Up = 0x4,
        Down = 0x8
    }
}